package svc.elib.analysis;

import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

import svc.elib.db.Author;
import svc.elib.db.Database;
import svc.elib.socnet.CentralityMetrics;
import svc.elib.socnet.ConnectedComponents;
import svc.elib.socnet.Net;
import svc.elib.socnet.SocConstructor;
import svc.elib.socnet.TrivialComponents;

public class RankPerComponent {

	class AInfo {
		String name;
		int numPapers, activity, degree, bet;
		double CC;
		
		int degR, numPapersR, activityR, betR, CCR;
		
		public AInfo(String name, int numPapers, int activity, int degree, int bet, double CC) {
			this.name = name;
			this.numPapers = numPapers;
			this.activity = activity;
			this.degree = degree;
			this.bet = bet;
			this.CC = CC;
		}
		
		public void dump() {
			System.out.println(name + ", " + degree + ", " + numPapers + ", " + numPapersR
					+ ", " + activity + ", " + activityR + ", " + bet + ", " + betR + ", " + CC);
		}
		
		public void dumpLatex() {
			StringBuilder sb = new StringBuilder();
			sb.append(name).append(" & ")
			  .append(degree).append(" & ")
			  .append(numPapers).append(" & ")
			  .append(numPapersR).append(" & ")
			  .append(activity).append(" & ")
			  .append(activityR).append(" & ")
			  .append(bet).append(" & ")
			  .append(betR).append(" & ")
			  .append(CC).append(" \\\\ ");
			;
			
			System.out.println(sb.toString());
		}
	}
	
	
	class PapersComp implements Comparator<AInfo> {
		@Override
		public int compare(AInfo arg0, AInfo arg1) {
			return arg1.numPapers - arg0.numPapers;
		}
	}
	
	class ActivityComp implements Comparator<AInfo> {
		@Override
		public int compare(AInfo o1, AInfo o2) {
			return o2.activity - o1.activity;
		}
		
	}
	
	class DegreeComp implements Comparator<AInfo> {
		@Override
		public int compare(AInfo o1, AInfo o2) {
			return o2.degree - o1.degree;
		}
		
	}
	
	class BetComp implements Comparator<AInfo> {
		@Override
		public int compare(AInfo o1, AInfo o2) {
			return o2.bet - o1.bet;
		}
		
	}
	
	class CCComp implements Comparator<AInfo> {
		@Override
		public int compare(AInfo o1, AInfo o2) {
			if (o1.CC > o2.CC)
				return 1;
			else
			if (o1.CC < o2.CC)
				return -1;
			else
				return 0;
		}
		
	}
	
	private LinkedList<Net> components;
	
	private TrivialComponents tc;
	
	private HashMap<Author, AInfo> authorMap = 
		new HashMap<Author, AInfo>();
	
	private LinkedList<AInfo> aList = new LinkedList<AInfo>();
	private LinkedList<AInfo> copy = new LinkedList<AInfo>();
	
	public RankPerComponent(Net net) {
		CentralityMetrics cm = new CentralityMetrics(net);
		cm.computeBetweeness(false);
		
		
		Iterator<Author> ait = net.getGraph().getVertices().iterator();
		while (ait.hasNext()) {
			Author a = ait.next();
			int bet = (int) cm.getBetweenness(a.getName());
			int deg = net.getGraph().degree(a);
			int activity = a.getActivitySpan();
			int numPapers = a.getNumPapers();
			double CC = net.getCC(a);
			
			AInfo ainfo = new AInfo(a.getName(), numPapers, activity, deg, bet, CC);
			aList.add(ainfo);
			copy.add(ainfo);
			authorMap.put(a, ainfo);
		}
		
		ConnectedComponents cn = new ConnectedComponents(net);
		cn.resolveComponents();
		components = cn.getComponents();
		
		tc = new TrivialComponents(net);
	}
	
	
	private void calculateRankings() {
		for (int i = 0; i < aList.size(); i++) {
			AInfo author = aList.get(i);
			String name = author.name;
			
			Collections.sort(copy, new PapersComp());
			author.numPapersR = 1;
			for (int j = 0; j < copy.size(); j++) {
				AInfo current = copy.get(j);
				
				if (j > 0) {
					AInfo prev = copy.get(j - 1);
					if (current.numPapers < prev.numPapers) {
						author.numPapersR++;
					}
				}
				
				if (current.name.compareTo(name) == 0)
					break;
			}
			
			Collections.sort(copy, new ActivityComp());
			author.activityR = 1;
			for (int j = 0; j < copy.size(); j++) {
				AInfo current = copy.get(j);
				
				if (j > 0) {
					AInfo prev = copy.get(j - 1);
					if (current.activity < prev.activity) {
						author.activityR++;
					}
				}
				
				if (current.name.compareTo(name) == 0)
					break;
			}
			
			Collections.sort(copy, new BetComp());
			author.betR = 1;
			for (int j = 0; j < copy.size(); j++) {
				AInfo current = copy.get(j);
				
				if (j > 0) {
					AInfo prev = copy.get(j - 1);
					if (current.bet < prev.bet) {
						author.betR++;
					}
				}
				
				if (current.name.compareTo(name) == 0)
					break;
			}
			
			Collections.sort(copy, new DegreeComp());
			author.degR = 1;
			for (int j = 0; j < copy.size(); j++) {
				AInfo current = copy.get(j);
				
				if (j > 0) {
					AInfo prev = copy.get(j - 1);
					if (current.bet < prev.bet) {
						author.degR++;
					}
				}
				
				if (current.name.compareTo(name) == 0)
					break;
			}
		}
	}
	
	
	public void doComponentRank() {
		
		calculateRankings();
		
		for (int i = 0; i < components.size(); i++) {
			Net comp = components.get(i);
			if (tc.isTrivial2(comp))
				continue;
			
			Iterator<Author> ait = comp.getGraph().getVertices().iterator();
			
			LinkedList<Integer> degreeRank = new LinkedList<Integer>();
			LinkedList<Integer> betRank = new LinkedList<Integer>();
			LinkedList<Integer> activityRank = new LinkedList<Integer>();
			LinkedList<Integer> numPapersRank = new LinkedList<Integer>();
			
			while (ait.hasNext()) {
				Author a = ait.next();
				AInfo aInfo = authorMap.get(a);
				degreeRank.add(aInfo.degR);
				betRank.add(aInfo.betR);
				activityRank.add(aInfo.activityR);
				numPapersRank.add(aInfo.numPapersR);
			}
			
			double meanDegR = mean(degreeRank);
			double meanBetR = mean(betRank);
			double meanActivityR = mean(activityRank);
			double meanNumPaperR = mean(numPapersRank);
		
			System.out.println(comp.getNumNodes() + ", " + meanDegR + ", " + meanBetR + ", " + meanNumPaperR + ", " + meanActivityR);
		}		
 	}
	
	private double mean(LinkedList<Integer> l) {
		double sum = 0.0;
		for (int i = 0; i < l.size(); i++) {
			sum += l.get(i);
		}
		
		return sum / (double) l.size();
	}
	
	public static void main(String[] args) 
		throws IOException
	{
		Database db = new Database("eLibData.csv", 1932, 2011);
		SocConstructor soc = new SocConstructor(db);
		Net net = soc.getNet();
		net.printInfo();
		
		RankPerComponent rpc = new RankPerComponent(net);
		rpc.doComponentRank();
	}
	
}
